//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package board_chat_api_serv

import (
	"context"
	"math"
	"time"

	"gitcode.com/eteam/api-server/dao"
	"gitcode.com/eteam/api-server/dao/board_dao"
	"gitcode.com/eteam/api-server/dao/user_dao"
	"gitcode.com/eteam/api-server/notice_serv"
	"gitcode.com/eteam/proto-gen-go.git/board_chat_api"
	"gitcode.com/eteam/proto-gen-go.git/notices/notices_board"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

type BoardChatApiImpl struct {
	board_chat_api.UnimplementedBoardChatApiServer
}

func (apiImpl *BoardChatApiImpl) Send(ctx context.Context, req *board_chat_api.SendRequest) (*board_chat_api.SendResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_chat_api.SendResponse{
			Code:   board_chat_api.SendResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	if req.DrawId != "" {
		exist, err := board_dao.DrawInfoDao.Exist(ctx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &board_chat_api.SendResponse{
				Code:   board_chat_api.SendResponse_CODE_NO_DRAW,
				ErrMsg: "画稿不存在",
			}, nil
		}
	}

	exist, err := board_dao.MemberInfoDao.Exist(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_chat_api.SendResponse{
			Code:   board_chat_api.SendResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	msgId := uuid.NewString()
	nowTime := time.Now().UnixMilli()

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = board_dao.MsgInfoDao.Insert(sessCtx, &board_dao.MsgInfoDbItem{
			MsgId:      msgId,
			BoardId:    req.BoardId,
			DrawId:     req.DrawId,
			Content:    req.Content,
			SendUserId: sessItem.UserId,
			SendTime:   nowTime,
		})
		if err != nil {
			return nil, err
		}
		if req.DrawId != "" {
			err = board_dao.DrawInfoDao.SetLastChatTime(sessCtx, req.BoardId, req.DrawId, nowTime)
			if err != nil {
				return nil, err
			}
		}
		return &board_chat_api.SendResponse{
			Code:  board_chat_api.SendResponse_CODE_OK,
			MsgId: msgId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//发送通知
	go notice_serv.PublishToBoard(req.BoardId, &notices_board.NewChatMsgNotice{
		BoardId: req.BoardId,
		DrawId:  req.DrawId,
		MsgId:   msgId,
	})
	return ret.(*board_chat_api.SendResponse), nil
}

func (apiImpl *BoardChatApiImpl) ListAfter(ctx context.Context, req *board_chat_api.ListAfterRequest) (*board_chat_api.ListAfterResponse, error) {
	emptyList := []*board_chat_api.MsgInfo{}

	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_chat_api.ListAfterResponse{
			Code:    board_chat_api.ListAfterResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			MsgList: emptyList,
		}, nil
	}
	if req.DrawId != "" {
		exist, err := board_dao.DrawInfoDao.Exist(ctx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &board_chat_api.ListAfterResponse{
				Code:    board_chat_api.ListAfterResponse_CODE_NO_DRAW,
				ErrMsg:  "画稿不存在",
				MsgList: emptyList,
			}, nil
		}
	}
	exist, err := board_dao.MemberInfoDao.Exist(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_chat_api.ListAfterResponse{
			Code:    board_chat_api.ListAfterResponse_CODE_NO_PERMISSION,
			ErrMsg:  "没有权限",
			MsgList: emptyList,
		}, nil
	}

	cmpMsgItem, err := board_dao.MsgInfoDao.Get(ctx, req.BoardId, req.DrawId, req.MsgId)
	if err != nil {
		return &board_chat_api.ListAfterResponse{
			Code:    board_chat_api.ListAfterResponse_CODE_NO_MSG,
			ErrMsg:  "参考信息不存在",
			MsgList: emptyList,
		}, nil
	}
	lastMsgId, err := board_dao.MsgInfoDao.GetLastMsgId(ctx, req.BoardId, req.DrawId)
	if err != nil {
		return nil, err
	}
	msgItemList, err := board_dao.MsgInfoDao.ListAfter(ctx, req.BoardId, req.DrawId, cmpMsgItem.SendTime, int64(req.Limit))
	if err != nil {
		return nil, err
	}
	msgList, err := apiImpl.convertToMsgList(ctx, msgItemList)
	if err != nil {
		return nil, err
	}
	return &board_chat_api.ListAfterResponse{
		Code:      board_chat_api.ListAfterResponse_CODE_OK,
		MsgList:   msgList,
		LastMsgId: lastMsgId,
	}, nil
}

func (apiImpl *BoardChatApiImpl) ListBefore(ctx context.Context, req *board_chat_api.ListBeforeRequest) (*board_chat_api.ListBeforeResponse, error) {
	emptyList := []*board_chat_api.MsgInfo{}

	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_chat_api.ListBeforeResponse{
			Code:    board_chat_api.ListBeforeResponse_CODE_WRONG_SESSION,
			ErrMsg:  "会话不存在",
			MsgList: emptyList,
		}, nil
	}
	if req.DrawId != "" {
		exist, err := board_dao.DrawInfoDao.Exist(ctx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &board_chat_api.ListBeforeResponse{
				Code:    board_chat_api.ListBeforeResponse_CODE_NO_DRAW,
				ErrMsg:  "画稿不存在",
				MsgList: emptyList,
			}, nil
		}
	}
	exist, err := board_dao.MemberInfoDao.Exist(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_chat_api.ListBeforeResponse{
			Code:    board_chat_api.ListBeforeResponse_CODE_NO_PERMISSION,
			ErrMsg:  "没有权限",
			MsgList: emptyList,
		}, nil
	}
	cmpSendTime := time.Now().UnixMilli()
	if req.MsgId != "" {
		cmpMsgItem, err := board_dao.MsgInfoDao.Get(ctx, req.BoardId, req.DrawId, req.MsgId)
		if err != nil {
			return &board_chat_api.ListBeforeResponse{
				Code:    board_chat_api.ListBeforeResponse_CODE_NO_MSG,
				ErrMsg:  "参考信息不存在",
				MsgList: emptyList,
			}, nil
		}
		cmpSendTime = cmpMsgItem.SendTime
	}

	lastMsgId, err := board_dao.MsgInfoDao.GetLastMsgId(ctx, req.BoardId, req.DrawId)
	if err != nil {
		return nil, err
	}
	msgItemList, err := board_dao.MsgInfoDao.ListBefore(ctx, req.BoardId, req.DrawId, cmpSendTime, int64(req.Limit))
	if err != nil {
		return nil, err
	}
	msgList, err := apiImpl.convertToMsgList(ctx, msgItemList)
	if err != nil {
		return nil, err
	}
	return &board_chat_api.ListBeforeResponse{
		Code:      board_chat_api.ListBeforeResponse_CODE_OK,
		MsgList:   msgList,
		LastMsgId: lastMsgId,
	}, nil
}

func (apiImpl *BoardChatApiImpl) GetUnreadCount(ctx context.Context, req *board_chat_api.GetUnreadCountRequest) (*board_chat_api.GetUnreadCountResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_chat_api.GetUnreadCountResponse{
			Code:   board_chat_api.GetUnreadCountResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	if req.DrawId != "" {
		exist, err := board_dao.DrawInfoDao.Exist(ctx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &board_chat_api.GetUnreadCountResponse{
				Code:   board_chat_api.GetUnreadCountResponse_CODE_NO_DRAW,
				ErrMsg: "画稿不存在",
			}, nil
		}
	}
	exist, err := board_dao.MemberInfoDao.Exist(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_chat_api.GetUnreadCountResponse{
			Code:   board_chat_api.GetUnreadCountResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	lastSendTime := int64(math.MinInt64)
	stateItem, err := board_dao.MsgReadStateDao.Get(ctx, req.DrawId, sessItem.UserId)
	if err == nil {
		lastSendTime = stateItem.LastMsgSendTime
	}
	count, err := board_dao.MsgInfoDao.CountAfter(ctx, req.BoardId, req.DrawId, lastSendTime)
	if err != nil {
		return nil, err
	}
	return &board_chat_api.GetUnreadCountResponse{
		Code:        board_chat_api.GetUnreadCountResponse_CODE_OK,
		UnreadCount: count,
	}, nil
}

func (apiImpl *BoardChatApiImpl) ClearUnread(ctx context.Context, req *board_chat_api.ClearUnreadRequest) (*board_chat_api.ClearUnreadResponse, error) {
	sessItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &board_chat_api.ClearUnreadResponse{
			Code:   board_chat_api.ClearUnreadResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	if req.DrawId != "" {
		exist, err := board_dao.DrawInfoDao.Exist(ctx, req.BoardId, req.DrawId)
		if err != nil {
			return nil, err
		}
		if !exist {
			return &board_chat_api.ClearUnreadResponse{
				Code:   board_chat_api.ClearUnreadResponse_CODE_NO_DRAW,
				ErrMsg: "画稿不存在",
			}, nil
		}
	}
	exist, err := board_dao.MemberInfoDao.Exist(ctx, req.BoardId, sessItem.UserId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &board_chat_api.ClearUnreadResponse{
			Code:   board_chat_api.ClearUnreadResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	lastMsgTime, err := board_dao.MsgInfoDao.GetLastMsgTime(ctx, req.BoardId, req.DrawId)
	if err != nil {
		return nil, err
	}
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = board_dao.MsgReadStateDao.Set(sessCtx, &board_dao.MsgReadStateDbItem{
			DrawId:          req.DrawId,
			MemberUserId:    sessItem.UserId,
			LastMsgSendTime: lastMsgTime,
		})
		if err != nil {
			return nil, err
		}
		return &board_chat_api.ClearUnreadResponse{
			Code: board_chat_api.ClearUnreadResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*board_chat_api.ClearUnreadResponse), nil
}

func (apiImpl *BoardChatApiImpl) convertToMsgList(ctx context.Context, msgItemList []*board_dao.MsgInfoDbItem) ([]*board_chat_api.MsgInfo, error) {
	userIdList := []string{}
	for _, msgItem := range msgItemList {
		userIdList = append(userIdList, msgItem.SendUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	//生成结果
	msgList := []*board_chat_api.MsgInfo{}
	for _, msgItem := range msgItemList {
		msg := msgItem.ToMsgInfo()
		sendUser, ok := userItemMap[msgItem.SendUserId]
		if ok {
			msg.SendDisplayName = sendUser.BasicInfo.DisplayName
			msg.SendLogoUri = sendUser.BasicInfo.LogoUri
		}
		msgList = append(msgList, msg)
	}
	return msgList, nil
}
